const express = require('express');
const crypto = require('@wecom/crypto');
const xml2js = require('xml2js');
const { promisify } = require('util');
const path = require('path');
const fs = require('fs');
const addon = require('./wework/lib/wework.node'); // 引入插件

// 配置信息
const TOKEN = process.env.WECOM_TOKEN || 'ipjSrT9pDDq0eHWN2HsAw5';
const ENCODING_AES_KEY = process.env.WECOM_ENCODING_AES_KEY || 'J7rGrFV99ASDo9fVaiNYsMQkxWOafGTFdWZkIN4YY4L'; 
const CORP_ID = process.env.WECOM_CORP_ID || 'wx9e04d92a62846a6a';
const SECRET = process.env.WECOM_SECRET || 'OQ7zbA7k_VgHXlk_pzgXz_dL-94KhTIlFOwna3brKDc';
const PORT = process.env.PORT || 3000;

// RSA 私钥
const PRI_KEY = `-----BEGIN PRIVATE KEY-----
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCXyWSEDksPGry6
CKy+oFMSPWD3NZA4BqdsOBjd4LUJrH1CD/SZpsj5vuP2rCtROP1S+EJUaJegWnaq
gZxOkE1ny8HX+82FzSrGRWXREAaIEBl57SyX6T/ep+wCuaxvm4jy/drvKrGEIHRs
KKn4FqCKrgnW4c39Q0xfIAEYf/SJ1UivOFAXGrEmllIgEz+p94sl4yLhfI5I84L6
8qghlI7OVSZ6nP1TSN6WPuvIWzHgGWxK0LFJ4H/zJPDNN1AUbeTn1c8AUKjI6seK
MXofK9qLU/8QaILARdLreAHTWcP+Fl7j5tRH82+R+1c3zOdaWpUvae1IVOoTOtpO
3DD+AhibAgMBAAECggEAEidPOG9ghm8bXkvro9BB+d78ag9DxJJLKNQcE+wBoFAQ
b7u/yeFa4mp0Z6FXfEXgH7G7ISRHP4bs8AnuBgQX4I+hNfHoNpX/Wn+cpKCRihQU
L/MapRU2WIIQkJI2BOfUZ8IjvVIHsXaTkLIGWLpqu1tYUupmZrbLULSKXQHvXyKY
1hK2PorA8OBGk8dEcIq0TmQ174NnZr3z5QTzdPIG72FkOHtsXo7spmb6HLhEBGWE
PAQZU9etX3V2t2YcHdJ9+40XDIuLHSMaYImkBEzc5VdJehSwRoybHOjBD7GM2vI5
2r/Drrs4YN5SogM1byMx6mmM36SzS5Z+BGkg4OzUWQKBgQDHMJ7eL/9aa2TygNv+
Up3Yh8xIuG2xMAifLvF9iFPR8nsSRih/nIJ1rR0V0GvMZjciQKmV3off5LcHVrKM
PrNHlwzoUbI2phQ8CQwPImmDl4teQ8IV1eGrgBVJDcCiJuOilyhVtJRpC476gAqP
/MgRqVLUfP7SKzowYB1GBOBiaQKBgQDDE7zKLokqmNDbdAWOC6/qgfvza+t08WtQ
C9bo4LhwCdU5uxEdZ1LgbWHP7N9iiWsfVExJGON/NiqaekDH/vLbb08r4VlPEECj
JtPu4lGcPDxJHX2l10LpNhOq4cOumlfcZo77FXZBKhtQim5nrz8/v9R7QShIh1QT
ZxGHcuZ6YwKBgCVx3mumWjqFNdTgpHqKzWGHJcAF65kDjpteF8eheSBelQQ6bCKR
KXU1teID7D/gdzzZKwghbSmJtV6LzcTPhKRQoPyLXxUm42blzH6L2YoDUw/FbRbt
vh6fVWEGVNAmv2QxRkPWTo/wvFAbAeFPg8zOJ+QKG10nAylU6Cvhfs0BAoGAZn14
MsFAT6D6GlJamMaLJioktT999XLhbqzJvJBUVojT/gDKfShL4p2VRiitNJf+L/ea
HM12uN88guy4HFtWPPO+JM/AnEltrEo6DsfZGLyM790OppLyFJTUwHLc3F86yhEY
DdK4zoPQ1f/lAZSRJm0itZ8GCxUOlyMPkppLfQECgYB6RXrkXQFh1VVE0Z+dbTA0
PalHgUis5aX5Wh+Y6/p1BIuoOGugz4TZr7iUgfRpmZ01YVp+yMRWOwfZyK+AR8/a
1Zhx0su0qGeFSbSpUYJdIHUhAjQTe1fAbGJsEKmr68ITIe4SQafi7M61+cVwRMVq
SMp33dYbnHguezlApy0MbA==
-----END PRIVATE KEY-----`;

// XML 解析器配置
const parseXML = promisify(new xml2js.Parser({ explicitArray: false, trim: true }).parseString);
const builder = new xml2js.Builder({ cdata: true, headless: true });

// 初始化插件
console.log('初始化企业微信插件...');
const initResult = addon.init(CORP_ID, SECRET);
console.log(`插件初始化结果: ${initResult} ${initResult === 0 ? '成功' : '失败'}`);

if (initResult !== 0) {
  console.error('错误: 插件初始化失败，请检查CORP_ID和SECRET');
  process.exit(1);
}

// 错误码解释函数
function getErrorMsg(code) {
  const errors = {
    0: '成功',
    10001: '参数错误',
    10002: '网络错误',
    10003: '数据解析失败',
    10004: '系统失败',
    10005: '密钥错误',
    10006: 'fileid错误',
    10007: '解密失败',
    10008: '会话存档已过期'
  };
  return errors[code] || `未知错误 (${code})`;
}

// RSA 密钥验证函数
function validatePrivateKey() {
  try {
    const crypto = require('crypto');
    const sign = crypto.createSign('RSA-SHA256');
    sign.update('test');
    const signature = sign.sign(PRI_KEY, 'base64');
    console.log('RSA 密钥验证成功');
    return true;
  } catch (e) {
    console.error('RSA 密钥验证失败:', e.message);
    return false;
  }
}

// 启动时验证 RSA 密钥
if (!validatePrivateKey()) {
  console.error('错误: RSA 私钥配置错误，请检查格式是否正确');
  process.exit(1);
}

// RSA 解密函数
function rsaDecryptRandomKey(encryptedKey) {
  const crypto = require('crypto');
  try {
    const buffer = Buffer.from(encryptedKey, 'base64');
    const decrypted = crypto.privateDecrypt(
      {
        key: PRI_KEY,
        padding: crypto.constants.RSA_PKCS1_PADDING
      },
      buffer
    );
    return decrypted.toString('utf8');
  } catch (error) {
    console.error('RSA 解密失败:', error.message);
    return null;
  }
}

const app = express();

// 中间件配置
app.use(express.urlencoded({ extended: true }));
app.use(express.text({ type: 'text/xml' }));

// GET 请求验证 URL 有效性
app.get('/callback', (req, res) => {
  const { msg_signature, timestamp, nonce, echostr } = req.query;
  
  if (!msg_signature || !timestamp || !nonce || !echostr) {
    return res.status(400).send('参数缺失');
  }

  const calculatedSignature = crypto.getSignature(
    TOKEN, 
    timestamp, 
    nonce, 
    echostr
  );

  if (calculatedSignature !== msg_signature) {
    console.error('签名验证失败', {
      接收签名: msg_signature,
      计算签名: calculatedSignature
    });
    return res.status(403).send('签名验证失败');
  }

  const { message } = crypto.decrypt(ENCODING_AES_KEY, echostr);
  res.set('Content-Type', 'text/plain');
  res.send(message);
});

// POST请求处理消息接收
app.post('/callback', async (req, res) => {
  try {
    const { msg_signature, timestamp, nonce } = req.query;
    
    if (!msg_signature || !timestamp || !nonce) {
      return res.status(400).send('参数缺失');
    }

    const xmlData = req.body;
    const result = await parseXML(xmlData);
    const encryptMsg = result.xml.Encrypt;
    
    if (!encryptMsg) {
      return res.status(400).send('无效的消息格式');
    }

    const calculatedSignature = crypto.getSignature(
      TOKEN, 
      timestamp, 
      nonce, 
      encryptMsg
    );

    if (calculatedSignature !== msg_signature) {
      console.error('签名验证失败', {
        接收签名: msg_signature,
        计算签名: calculatedSignature
      });
      return res.status(403).send('签名验证失败');
    }

    const decrypted = crypto.decrypt(ENCODING_AES_KEY, encryptMsg);
    const message = await parseXML(decrypted.message);
    
    console.log('收到消息:', JSON.stringify(message.xml, null, 2));
    
    const response = await handleMessage(message.xml);
    
    if (response) {
      const encryptResponse = crypto.encrypt(ENCODING_AES_KEY, response);
      const newTimestamp = Math.floor(Date.now() / 1000).toString();
      const newNonce = Math.random().toString(36).substring(2, 15);
      
      const responseSignature = crypto.getSignature(
        TOKEN,
        newTimestamp,
        newNonce,
        encryptResponse
      );
      
      const responseXml = builder.buildObject({
        xml: {
          Encrypt: encryptResponse,
          MsgSignature: responseSignature,
          TimeStamp: newTimestamp,
          Nonce: newNonce
        }
      });
      
      res.set('Content-Type', 'application/xml');
      return res.send(responseXml);
    }
    
    res.status(200).end('');
    
  } catch (error) {
    console.error('处理消息时出错:', error);
    res.status(500).send('服务器内部错误');
  }
});

// 会话存档接口 - 使用 wework.node 插件
app.get('/archive', async (req, res) => {
  try {
    // 1. 解析参数
    const seq = parseInt(req.query.seq || '0');
    let limit = parseInt(req.query.limit || '10');
    
    // 限制最大拉取数量
    if (limit > 1000) {
      limit = 1000;
      console.log(`限制拉取数量为最大值: 1000`);
    }
    
    console.log(`获取会话存档: seq=${seq}, limit=${limit}`);

    // 2. 调用插件获取聊天数据
    const data = addon.getChatData(seq, limit, '', '', 60);
    const json = JSON.parse(data);
    
    // 3. 检查错误
    if (json.errcode !== 0) {
      console.error('获取聊天记录失败:', {
        errcode: json.errcode,
        errmsg: json.errmsg
      });
      return res.status(500).json(json);
    }
    
    console.log(`获取到 ${json.chatdata?.length || 0} 条聊天记录`);
    
    const decryptedMessages = [];
    
    // 4. 解密每条消息
    if (json.chatdata && json.chatdata.length > 0) {
      for (const msg of json.chatdata) {
        try {
          // 4.1 RSA 解密随机密钥
          const randomKey = rsaDecryptRandomKey(msg.encrypt_random_key);
          if (!randomKey) {
            console.error('解密随机密钥失败');
            continue;
          }
          
          // 4.2 解密消息内容
          const decryptedContent = addon.decryptdata(randomKey, msg.encrypt_chat_msg);
          if (!decryptedContent) {
            console.error('解密消息内容失败');
            continue;
          }
          
          // 4.3 解析消息内容
          try {
            const messageObj = JSON.parse(decryptedContent);
            decryptedMessages.push({
              seq: msg.seq,
              msgid: msg.msgid,
              publickey_ver: msg.publickey_ver,
              ...messageObj
            });
          } catch (e) {
            console.error('解析解密后的消息失败:', e);
            decryptedMessages.push({
              seq: msg.seq,
              msgid: msg.msgid,
              error: '解析消息失败',
              raw: decryptedContent
            });
          }
        } catch (e) {
          console.error('处理单条消息出错:', e);
        }
      }
    }
    
    // 5. 返回结果
    res.json({ 
      errcode: 0,
      errmsg: 'ok',
      next_seq: json.next_seq || (seq + decryptedMessages.length),
      messages: decryptedMessages
    });
    
  } catch (error) {
    console.error('获取会话存档出错:', error);
    res.status(500).json({ 
      errcode: 500,
      errmsg: '服务器内部错误'
    });
  }
});

// SDK 状态检查接口
app.get('/sdk-status', (req, res) => {
  res.json({
    initialized: initResult === 0,
    initResult,
    errorMsg: getErrorMsg(initResult),
    rsaValid: validatePrivateKey(),
    env: {
      token: TOKEN.substring(0, 4) + '...',
      encodingAESKey: ENCODING_AES_KEY.substring(0, 4) + '...',
      corpId: CORP_ID,
      secret: SECRET.substring(0, 4) + '...'
    }
  });
});

// 消息处理函数
async function handleMessage(message) {
  const msgType = message.MsgType;
  if (msgType === 'text') {
    return buildTextMessage(
      message.FromUserName,
      message.ToUserName,
      `已收到您的消息：${message.Content}`
    );
  }
  if (msgType === 'event') {
    const eventType = message.Event;
    switch (eventType) {
      case 'subscribe':
        return buildTextMessage(
          message.FromUserName,
          message.ToUserName,
          '欢迎关注！发送任意消息开始互动'
        );
      case 'unsubscribe':
        console.log(`用户 ${message.FromUserName} 取消关注`);
        return null;
      case 'click':
        return buildTextMessage(
          message.FromUserName,
          message.ToUserName,
          `您点击了菜单: ${message.EventKey}`
        );
    }
  }
  return buildTextMessage(
    message.FromUserName,
    message.ToUserName,
    `暂不支持${msgType}类型的消息`
  );
}

// 构建文本回复消息
function buildTextMessage(toUser, fromUser, content) {
  return builder.buildObject({
    xml: {
      ToUserName: { _: toUser },
      FromUserName: { _: fromUser },
      CreateTime: Math.floor(Date.now() / 1000),
      MsgType: { _: 'text' },
      Content: { _: content }
    }
  });
}

// 启动服务
app.listen(PORT, () => {
  console.log(`=============================================`);
  console.log(`企业微信回调服务已启动`);
  console.log(`服务地址: http://localhost:${PORT}/callback`);
  console.log(`存档接口: http://localhost:${PORT}/archive?seq=0&limit=100`);
  console.log(`状态检查: http://localhost:${PORT}/sdk-status`);
  console.log(`Token: ${TOKEN}`);
  console.log(`EncodingAESKey: ${ENCODING_AES_KEY}`);
  console.log(`CorpID: ${CORP_ID}`);
  console.log(`Secret: ${SECRET}`);
  console.log('=============================================');
});